package org.aceor.mddal.gateway.executor;

import org.aceor.mddal.common.executor.ExecuteUnit;
import org.aceor.mddal.gateway.executor.impl.DefaultQueryMergeUnit;
import org.aceor.mddal.gateway.executor.impl.DefaultUpdateMergeUnit;
import org.apache.commons.collections.CollectionUtils;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

/**
 * 多线程执行预编译语句对象请求的执行器.
 * 后续可以与StatementExecutor整合,两者存在不少一样的逻辑代码
 */
public final class PreparedStatementExecutor {

    private final ExecutorEngine executorEngine;

    private final Collection<PreparedStatement> preparedStatements;

    private final ExecuteContext executeContext;

    public PreparedStatementExecutor(ExecuteContext executeContext, Collection<PreparedStatement> statements) {
        this.executorEngine = ExecutorEngineFactory.getInstance();
        this.preparedStatements = statements;
        this.executeContext = executeContext;
    }

    /**
     * 执行SQL查询.
     *
     * @return 结果集列表
     * @throws SQLException SQL异常
     */
    public ResultSet executeQuery() throws SQLException {
        ResultSet result;
        if (1 == preparedStatements.size()) {
            result = preparedStatements.iterator().next().executeQuery();
            return result;
        }
        result = executorEngine.execute(preparedStatements, new ExecuteUnit<PreparedStatement, ResultSet>() {

            @Override
            public ResultSet execute(final PreparedStatement input) throws Exception {
                return input.executeQuery();
            }
        }, new DefaultQueryMergeUnit(executeContext.mergeContext));
        return result;
    }

    /**
     * 执行SQL更新.
     *
     * @return 更新数量
     * @throws SQLException SQL异常
     */
    public int executeUpdate() throws SQLException {
        int result;
        if (1 == preparedStatements.size()) {
            result = preparedStatements.iterator().next().executeUpdate();
            return result;
        }
        result = executorEngine.execute(preparedStatements, new ExecuteUnit<PreparedStatement, Integer>() {

            @Override
            public Integer execute(final PreparedStatement input) throws Exception {
                return input.executeUpdate();
            }
        }, new DefaultUpdateMergeUnit());
        return result;
    }

    /**
     * 执行SQL请求.
     *
     * @return true表示执行DQL, false表示执行的DML
     * @throws SQLException SQL异常
     */
    public boolean execute() throws SQLException {
        if (1 == preparedStatements.size()) {
            boolean result = preparedStatements.iterator().next().execute();
            return result;
        }
        List<Boolean> result = executorEngine.execute(preparedStatements, new ExecuteUnit<PreparedStatement, Boolean>() {

            @Override
            public Boolean execute(final PreparedStatement input) throws Exception {
                return input.execute();
            }
        });
        return result.get(0);
    }

    public static PreparedStatementExecutorHolder build() {
        return new PreparedStatementExecutorHolder();
    }

    public static class PreparedStatementExecutorHolder {
        private ExecuteContext executeContext;
        private Collection<PreparedStatement> statements;

        public PreparedStatementExecutorHolder setStatementEntities(Collection<PreparedStatement> psts) {
            statements = psts;
            return this;
        }

        public PreparedStatementExecutorHolder setExecuteContext(ExecuteContext executeContext) {
            this.executeContext = executeContext;
            return this;
        }

        public PreparedStatementExecutor create() {
            if (null == executeContext) {
                throw new RuntimeException("ExecuteContext 不能为空");
            }
            if (CollectionUtils.isEmpty(statements)) {
                throw new RuntimeException("PreparedStatement集合不能为空");
            }
            return new PreparedStatementExecutor(executeContext, statements);
        }
    }
}
